#include "ComPort.h"
#include <stdio.h>
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <vector>

namespace
{
	void *recv_msg_thread(void *ptr)
	{
		com_port *_com_port = (com_port *)ptr;
		_com_port->recv_msg();
	}

	void *send_msg_thread(void *ptr)
	{
		com_port *_com_port = (com_port *)ptr;
		_com_port->send_msg();	
	}

	int set_interface_attribs(int fd, int speed)
	{
	    struct termios tty;

	    if (tcgetattr(fd, &tty) < 0) {
	        // printf("Error from tcgetattr: %s\n", strerror(errno));
	        perror("Error from tcgetattr");
	        return -1;
	    }

	    cfsetospeed(&tty, (speed_t)speed);
	    cfsetispeed(&tty, (speed_t)speed);

	    tty.c_cflag |= (CLOCAL | CREAD);    /* ignore modem controls */
	    tty.c_cflag &= ~CSIZE;
	    tty.c_cflag |= CS8;         /* 8-bit characters */
	    tty.c_cflag &= ~PARENB;     /* no parity bit */
	    tty.c_cflag &= ~CSTOPB;     /* only need 1 stop bit */
	    tty.c_cflag &= ~CRTSCTS;    /* no hardware flowcontrol */

	    /* setup for non-canonical mode */
	    tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
	    tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
	    tty.c_oflag &= ~OPOST;

	    /* fetch bytes as they become available */
	    tty.c_cc[VMIN] = 1;
	    tty.c_cc[VTIME] = 1;

	    if (tcsetattr(fd, TCSANOW, &tty) != 0) {
	    	perror("Error from tcsetattr");
	        // printf("Error from tcsetattr: %s\n", strerror(errno));
	        return -1;
	    }
	    return 0;
	}

	void set_mincount(int fd, int mcount)
	{
	    struct termios tty;

	    if (tcgetattr(fd, &tty) < 0) {
	    	perror("Error tcgetattr");
	        // printf("Error tcgetattr: %s\n", strerror(errno));
	        return;
	    }

	    tty.c_cc[VMIN] = mcount ? 1 : 0;
	    tty.c_cc[VTIME] = 5;        /* half second timer */

	    if (tcsetattr(fd, TCSANOW, &tty) < 0)
	    	perror("Error tcsetattr");
	        // printf("Error tcsetattr: %s\n", strerror(errno));
	}
}

void com_port::recv_buffer(int fd)
{
	int ret = 0;
	char tmp[500];

	fd_set set;

	while(1)
	{
		int tmp_ret = read(fd, tmp, sizeof(tmp));
		if(tmp_ret <= 0)
		{
			close(fd);

			std::cout << "com port socket " << fd << std::endl;

			for (int i = 0; i < MAX_COM_PORT_COUNT; ++i)
			{
				if(com_port_fd_list[i] == fd)
					com_port_fd_list[i] = 0;
			}
		}
		// else
		// {
		// 	if (tmp_ret < COM_PORT_BUF_SIZE)
		// 		memset(&buf[tmp_ret], '\0', 1);



		// 	// std::cout << buf << std::endl;
		// }

		memcpy(buf + ret, tmp, sizeof(char) * tmp_ret);

		ret += tmp_ret;
		if (ret >= sizeof(buf))
		{
			std::cout << ret << " >= " << sizeof(buf) << std::endl;
			break;
		}
		
		FD_ZERO(&set);
		FD_SET(fd, &set);

		struct timeval tv;
		tv.tv_sec = 0;
		tv.tv_usec = 10000;		// 毫秒 + 000

		if(select(fd + 1, &set, NULL, NULL, &tv) == 0)
		{
			std::cout << "no select message" << std::endl;
			break;
		}
	}

	if (ret < COM_PORT_BUF_SIZE)
		memset(&buf[ret], '\0', 1);

	std::cout << buf << std::endl;

	Message message;
	message.com_port = fd2com_port[fd];
	memcpy(message.message, buf, ret + 1);			// max str len message.message = 1024 max ret = 1000
	_recv_message_queue->push_message(message);
}

com_port::com_port()
{
	int i = 0;
	max_com_port_fd = 0;

	std::vector<std::string> device_names;
	device_names.push_back("/dev/ttyS9");
	device_names.push_back("/dev/ttyS3");
	device_names.push_back("/dev/ttyS2");
	device_names.push_back("/dev/ttyS8");
	device_names.push_back("/dev/ttyS5");
	device_names.push_back("/dev/ttyS6");
	device_names.push_back("/dev/ttyS10");
	device_names.push_back("/dev/ttyS7");
	device_names.push_back("/dev/ttySAC0");
	device_names.push_back("/dev/ttySAC1");
	device_names.push_back("/dev/ttySAC2");
	device_names.push_back("/dev/ttySAC3");
	device_names.push_back("/dev/ttySAC4");
	device_names.push_back("/dev/ttySAC5");
	device_names.push_back("/dev/ttySAC6");
	device_names.push_back("/dev/ttySAC7");

	for (std::vector<std::string>::iterator ptr = device_names.begin(); ptr != device_names.end(); ++ptr)
	{
		int com_port_fd = open((*ptr).c_str(), O_RDWR | O_NOCTTY | O_SYNC);
		
	    if(-1 == com_port_fd)
	    {
	        std::cout << (*ptr).c_str() << " open fail" << std::endl;
	        continue;
	    }

	    com_port2fd[ptr - device_names.begin() + 1] = com_port_fd;
	    fd2com_port[com_port_fd] = ptr - device_names.begin() + 1;

	    std::cout << "open com_port " << *ptr << " com_port fd " << com_port_fd << std::endl;

	    if(com_port_fd > max_com_port_fd)
	    	max_com_port_fd = com_port_fd;

	    set_interface_attribs(com_port_fd, B9600);

		// struct termios oldstdio;
	 //    tcgetattr(com_port_fd, &oldstdio);
	 //    cfsetispeed(&oldstdio, B9600);
	 //    tcsetattr(com_port_fd, TCSANOW, &oldstdio);
	 //    tcflush(com_port_fd, TCIFLUSH);

	    bool is_find = false;
	    for (; i < MAX_COM_PORT_COUNT; ++i)
	    {
	    	if(com_port_fd_list[i] == 0)
	    	{
	    		com_port_fd_list[i] = com_port_fd;
	    		is_find = true;
	    		break;
	    	}
	    }

	    if(!is_find)
	    	throw "No vacancy for com port";
	}
}

void com_port::recv_msg()
{
	fd_set recv_set;

	int recVal;

	while(1)
	{
		FD_ZERO(&recv_set);
		for (int i = 0; i < MAX_COM_PORT_COUNT; ++i)
		{
			if(com_port_fd_list[i] != 0)
				FD_SET(com_port_fd_list[i], &recv_set);
		}


		struct timeval tv;
		tv.tv_sec = 1;
		tv.tv_usec = 0.0;
		recVal = select(max_com_port_fd + 1, &recv_set, NULL, NULL, &tv);

		switch(recVal)
	    {
	        case(0):
	        {
	        	// std::cout << "com_port recv time out" << std::endl;
	            break;
	        }
	        case(-1):
	        {
	        	perror("recv error");
	            break;
	        }
	        default:
	        {   
	        	for (int i = 0; i < MAX_COM_PORT_COUNT; ++i)
	        	{
	        		if(com_port_fd_list[i] != 0 && FD_ISSET(com_port_fd_list[i], &recv_set))
	        		{
	        			std::cout << "new recv data " << com_port_fd_list[i] << std::endl;
	        			recv_buffer(com_port_fd_list[i]);
	        		}	
	        	}

	            break;
	        }
	    }
	}
}

void com_port::send_msg()
{
	while(1)
	{
		struct Message message = _message_queue->pop_message();
		std::cout << "哇 获取到一个消息" << std::endl;

		int fd = com_port2fd[message.com_port];
		write(fd, message.message, strlen(message.message));
	}
}

bool com_port::start_recv_msg(MessageQueue * mq)
{
	_recv_message_queue = mq;

	int ret = pthread_create(&thread_recv_msg, NULL, recv_msg_thread, this);
	if(ret)
	{
		std::cout << "create pthread error" << std::endl;
		return false;
	}

	return true;
}
	
bool com_port::stop_recv_msg()
{
	pthread_exit(&thread_recv_msg);
	return true;
}

bool com_port::start_send_msg(MessageQueue * mq)
{
	_message_queue = mq;
	int ret = pthread_create(&thread_send_msg, NULL, send_msg_thread, this);
	if (ret)
	{
		std::cout << "create pthread error" << std::endl;
		return false;	
	}

	return true;
}

bool com_port::stop_send_msg()
{
	pthread_exit(&thread_send_msg);
	return true;
}
